package com.whcoding.base.project.service.impl;


import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.whcoding.base.project.common.BasicBeanUtil;
import com.whcoding.base.project.common.CSVUtils;
import com.whcoding.base.project.common.MybatisBatchUtils;
import com.whcoding.base.project.common.BasicsPageUtil;
import com.whcoding.base.project.common.api.AppCode;
import com.whcoding.base.project.dao.DeptDao;
import com.whcoding.base.project.dao.DeptMapper;
import com.whcoding.base.project.exception.APIException;
import com.whcoding.base.project.pojo.CarrierPO;
import com.whcoding.base.project.pojo.OrmDeptCondition;
import com.whcoding.base.project.pojo.OrmDeptPO;
import com.whcoding.base.project.pojo.OrmDeptVO;
import com.whcoding.base.project.service.DeptService;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.data.domain.Page;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.*;

/**
 * @author Manager
 */
@Service
public class DeptServiceImpl implements DeptService {

	private static final Logger log = LoggerFactory.getLogger(DeptServiceImpl.class);

	@Autowired
	private DeptDao deptDao;

	@Autowired
	private DeptMapper deptMapper;

	@Autowired
	MybatisBatchUtils mybatisBatchUtils;

	/**
	 * 编程式事务
	 */
	@Autowired
	TransactionTemplate transactionTemplate;

	/**
	 * 实现批量写入
	 * 需要增加 rewriteBatchedStatements=true在yml文件的jdbc上
	 */
	@Autowired
	SqlSessionFactory sqlSessionFactory;

	/**
	 * 新增数据
	 *
	 * @param deptVO
	 * @return
	 */
	@Override
	public boolean addDept(OrmDeptVO deptVO) {
		return deptMapper.addDept(deptVO) > 0;
	}

	/**
	 * 查询数据-ID
	 *
	 * @param id
	 * @return
	 */
	@Override
	public OrmDeptVO queryDeptById(Long id) {
//		try {
//			Thread.sleep(60000);
//		} catch (InterruptedException e) {
//			log.info("恢复中断 ");
//		}
		OrmDeptVO ormDeptVO = deptMapper.queryDeptById(id);

		if (null == ormDeptVO) {
			//封装自自定义抛出异常
			throw new APIException(AppCode.DEPT_NOT_EXIST, "订单号不存在：" + ormDeptVO.getDeptName());
		}
		return deptMapper.queryDeptById(id);
	}

	/**
	 * 查询全部数据
	 *
	 * @return
	 */
	@Override
	public List<OrmDeptVO> queryAllDept() {
		return deptMapper.queryAllDept();
	}

	/**
	 * 更新数据
	 *
	 * @param deptVO vo
	 * @return
	 */
	@Override
	public boolean updateDept(OrmDeptVO deptVO) {
		return deptMapper.updateOrmDept(deptVO) > 0;
	}

	/**
	 * 删除数据
	 *
	 * @param ids 主键id
	 * @return
	 */
	@Override
	public void deleteByIds(List<Long> ids) {
		ids.forEach(c -> {
			deleteDeptById(c);
		});
	}

	/**
	 * 删除数据
	 *
	 * @param id 主键id
	 * @return
	 */
	@Override
	public boolean deleteDeptById(Long id) {
		return deptMapper.deleteOrmDeptById(id) > 0;
	}

	/**
	 * 删除或者更新
	 * 1.MYSQL中的ON DUPLICATE KEY UPDATE，是基于主键(PRIMARY KEY)或唯一索引(UNIQUE INDEX)使用的。
	 * 2.唯一索引/主键相同	更新原有数据
	 * 唯一索引/主键不同    插入新数据
	 * 3.如果已存在该唯一标示或主键就更新，如果不存在该唯一标示或主键则作为新行插入。
	 * 4.传递参数要修改主键 id
	 * 5.设置多列为 [唯一索引]
	 * ALTER TABLE `orm_dept` ADD UNIQUE INDEX ` UNIQ_TEMP` (`dept_id`, `dept_no`) USING BTREE
	 * 6.设置唯一索引 则instert 不需要写主键
	 * 7.根据主键更新则 instert 需要写主键
	 *
	 * @param id
	 */
	@Override
	public void insertOrUpdateBatch(Long id) {
		OrmDeptVO deptVO = deptMapper.queryDeptById(id);
		deptVO.setDeptId(1001);
		deptVO.setDeptNo("CG_888");
		deptVO.setUpdateTime(new Date());
		deptVO.setRemark(null);
		List<OrmDeptVO> deptVOS = Lists.newArrayList(deptVO);
		deptMapper.insertOrUpdateBatch(deptVOS);
	}


	/**
	 * 批量写入方法二：
	 * 开始sql batch
	 * 不推荐
	 *
	 * @param deptVOS
	 * @Transactional 声明式事务
	 */
	@Transactional(rollbackFor = Exception.class)
	public void batchInsert(List<OrmDeptVO> deptVOS) {
		SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
		long startTime = System.currentTimeMillis();
		for (OrmDeptVO deptVO : deptVOS) {
			deptMapper.addDeptOneByOne(deptVO);
		}
		session.commit();
		long endTime = System.currentTimeMillis();
		log.info("一条条插入 SQL 耗费时间 {}", (endTime - startTime));
	}


	/**
	 * 批量插入数据
	 *
	 * @param deptVOS
	 */
	public void batchInsertUtil(List<OrmDeptVO> deptVOS) {
		//方法一：不推荐
		mybatisBatchUtils.batchUpdateOrInsert(deptVOS, item -> deptMapper.addDept(item));
		//方法二：推荐
		mybatisBatchUtils.batchUpdateOrInsert(deptVOS, DeptMapper.class, (item, dao) -> dao.addDept(item));
	}


	@Override
	public void saveCarrierCsvFile() {
		String filePath = "E:\\temp\\carrier_20220310111404.csv";
		File file = new File(filePath);
		try {
			InputStream input = new FileInputStream(file);
			//CSV文件转为List
			List<CarrierPO> csvData = CSVUtils.getCsvData(input, CarrierPO.class);
			if (CollectionUtils.isEmpty(csvData)) {
				System.out.println("没有获取到数据");
			} else {
				deptMapper.insertCarrier(csvData);
			}
		} catch (Exception e) {
			System.out.println("转换失败，请检查数据！");
		}
		System.out.println("执行完成！");
	}

	/**
	 * 对数据进行分页查询
	 *
	 * @param deptCondition
	 * @return
	 */
	@Override
	public Page<OrmDeptVO> findDeptByPage(OrmDeptCondition deptCondition) {
		Pageable pageable = BasicsPageUtil.buildPageable(deptCondition.getPageParamVO());
		Map<String, Object> map = new HashMap<>(16);
		BasicBeanUtil.bean2map(deptCondition, map);
		BasicBeanUtil.bean2map(pageable, map);
		Integer count = deptMapper.countByDept(map);
		List<OrmDeptVO> list = Collections.emptyList();
		if (count > 0) {
			list = deptMapper.findByPageDept(map);
		}
		PageImpl page = new PageImpl(list, pageable, count);
		return page;
	}

	/**
	 * 多线程插入
	 */
	@Transactional(rollbackFor = Exception.class)
	public void threadsInsert() {
		int nThreads = 50;
		List<OrmDeptVO> deptVOList = deptMapper.queryAllDept();
		int size = deptVOList.size();

		/**
		 * corePoolSize线程池的核心线程数
		 * maximumPoolSize能容纳的最大线程数
		 * keepAliveTime空闲线程存活时间
		 * unit 存活的时间单位
		 * workQueue 存放提交但未执行任务的队列
		 * threadFactory 创建线程的工厂类
		 * handler 等待队列满后的拒绝策略
		 */
		ExecutorService executorService = new ThreadPoolExecutor
				(2,
						5,
						1L,
						TimeUnit.SECONDS,
						new LinkedBlockingQueue<>(3),
						Executors.defaultThreadFactory(),
						new ThreadPoolExecutor.AbortPolicy());

//		ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
		List<Future<Integer>> futures = new ArrayList<Future<Integer>>(nThreads);

		for (int i = 0; i < nThreads; i++) {
			Callable<Integer> task1 = () -> {
				deptMapper.insertOrUpdateBatch(deptVOList);
				return 1;
			};
			futures.add(executorService.submit(task1));
		}
		executorService.shutdown();
		if (!futures.isEmpty() && futures != null) {
			System.out.println(10);
		}
	}

	private void getDeptVo() {
		List<OrmDeptPO> deptVOS = deptDao.findAll();
		System.out.println(JSON.toJSON(deptVOS));
	}


	/**
	 * 使用编程式事务保存数据
	 */
	private OrmDeptVO transactionTemplateTest(OrmDeptVO deptVO) {
		//编程式事务保存数据
		transactionTemplate.execute((status) -> {
			deptDao.save(deptDao.findById(1).get());
			deptDao.save(deptDao.findById(1).get());
			return Boolean.TRUE;
		});

		OrmDeptVO resultDeptVO = (OrmDeptVO)
				this.transactionTemplate.execute(new TransactionCallback() {
					@Override
					public Object doInTransaction(TransactionStatus status) {
						// 查看数据是否存在 存在则返回主键
						Optional<OrmDeptPO> deptPOOptional = deptDao.findById(1);
						OrmDeptPO deptPO = deptPOOptional.isPresent() ? deptPOOptional.get() : null;
						if (deptVO.getDeptId().equals(deptPO.getDeptId())) {
							return deptPO;
						}
						return deptVO;

					}
				});

		if (deptVO.getDeptId().equals(resultDeptVO.getIsValidFlag())) {
			throw new RuntimeException("数据已经存在不能重新修改");
		}
		return deptVO;
	}

//	@Override
//	public Page<OrmDeptVO> findDeptByPage(OrmDeptCondition deptCondition) {
//		Pageable pageable = BasicsPageUtil.buildPageable(deptCondition.getPageParamVO());
//		Map<String, Object> map = new HashMap<>(16);
//		BasicBeanUtil.bean2map(deptCondition, map);
//		BasicBeanUtil.bean2map(pageable, map);
//		//根据参数查询数据
//		long totalCount = deptDao.count();
//		List<OrmDeptVO> cbdList = deptMapper.queryAllDept();
//		PageImpl page = new PageImpl(cbdList, pageable, totalCount == 0 ? 1000 : totalCount);
//		return page;
//	}
}
